home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / timed / timed.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-01-19  |  13.9 KB  |  627 lines

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. char copyright[] =
  15. "@(#) Copyright (c) 1985 Regents of the University of California.\n\
  16.  All rights reserved.\n";
  17. #endif /* not lint */
  18.  
  19. #ifndef lint
  20. static char sccsid[] = "@(#)timed.c    2.13 (Berkeley) 12/23/87";
  21. #endif /* not lint */
  22.  
  23. #include "globals.h"
  24. #define TSPTYPES
  25. #include <protocols/timed.h>
  26. #include <net/if.h>
  27. #include <sys/file.h>
  28. #include <sys/ioctl.h>
  29. #include <setjmp.h>
  30.  
  31. int id;
  32. int trace;
  33. int sock, sock_raw = -1;
  34. int status = 0;
  35. int backoff;
  36. int slvcount;                /* no. of slaves controlled by master */
  37. int machup;
  38. u_short sequence;            /* sequence number */
  39. long delay1;
  40. long delay2;
  41. long random();
  42. char hostname[MAXHOSTNAMELEN];
  43. struct host hp[NHOSTS];
  44. char tracefile[] = "/usr/adm/timed.log";
  45. FILE *fd;
  46. jmp_buf jmpenv;
  47. struct netinfo *nettab = NULL;
  48. int nslavenets;        /* Number of networks were I could be a slave */
  49. int nmasternets;    /* Number of networks were I could be a master */
  50. int nignorednets;    /* Number of ignored networks */
  51. int nnets;        /* Number of networks I am connected to */
  52. struct netinfo *slavenet;
  53. struct netinfo *firstslavenet();
  54. int Mflag;
  55. int justquit = 0;
  56.  
  57. struct nets {
  58.     char *name;
  59.     long net;
  60.     struct nets *next;
  61. } *nets = (struct nets *)0;
  62.  
  63. /*
  64.  * The timedaemons synchronize the clocks of hosts in a local area network.
  65.  * One daemon runs as master, all the others as slaves. The master
  66.  * performs the task of computing clock differences and sends correction
  67.  * values to the slaves. 
  68.  * Slaves start an election to choose a new master when the latter disappears 
  69.  * because of a machine crash, network partition, or when killed.
  70.  * A resolution protocol is used to kill all but one of the masters
  71.  * that happen to exist in segments of a partitioned network when the 
  72.  * network partition is fixed.
  73.  *
  74.  * Authors: Riccardo Gusella & Stefano Zatti
  75.  */
  76.  
  77. main(argc, argv)
  78. int argc;
  79. char **argv;
  80. {
  81.     int on;
  82.     int ret;
  83.     long seed;
  84.     int nflag, iflag;
  85.     struct timeval time;
  86.     struct servent *srvp;
  87.     long casual();
  88.     char *date();
  89.     int n;
  90.     int flag;
  91.     char buf[BUFSIZ];
  92.     struct ifconf ifc;
  93.     struct ifreq ifreq, *ifr;
  94.     register struct netinfo *ntp;
  95.     struct netinfo *ntip;
  96.     struct netinfo *savefromnet;
  97.     struct sockaddr_in server;
  98.     u_short port;
  99.     uid_t getuid();
  100.  
  101. #ifdef lint
  102.     ntip = NULL;
  103. #endif
  104.  
  105.     Mflag = 0;
  106.     on = 1;
  107.     backoff = 1;
  108.     trace = OFF;
  109.     nflag = OFF;
  110.     iflag = OFF;
  111.     openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
  112.  
  113.     if (getuid() != 0) {
  114.         fprintf(stderr, "Timed: not superuser\n");
  115.         exit(1);
  116.     }
  117.  
  118.     while (--argc > 0 && **++argv == '-') {
  119.         (*argv)++;
  120.         do {
  121.             switch (**argv) {
  122.  
  123.             case 'M':
  124.                 Mflag = 1; 
  125.                 break;
  126.             case 't':
  127.                 trace = ON; 
  128.                 break;
  129.             case 'n':
  130.                 argc--, argv++;
  131.                 if (iflag) {
  132.                     fprintf(stderr,
  133.                     "timed: -i and -n make no sense together\n");
  134.                 } else {
  135.                     nflag = ON;
  136.                     addnetname(*argv);
  137.                 }
  138.                 while (*(++(*argv)+1)) ;
  139.                 break;
  140.             case 'i':
  141.                 argc--, argv++;
  142.                 if (nflag) {
  143.                     fprintf(stderr,
  144.                     "timed: -i and -n make no sense together\n");
  145.                 } else {
  146.                     iflag = ON;
  147.                     addnetname(*argv);
  148.                 }
  149.                 while (*(++(*argv)+1)) ;
  150.                 break;
  151.             default:
  152.                 fprintf(stderr, "timed: -%c: unknown option\n", 
  153.                             **argv);
  154.                 break;
  155.             }
  156.         } while (*++(*argv));
  157.     }
  158.  
  159. #ifndef DEBUG
  160.     if (fork())
  161.         exit(0);
  162.     { int s;
  163.       for (s = getdtablesize(); s >= 0; --s)
  164.         (void) close(s);
  165.       (void) open("/dev/null", 0);
  166.       (void) dup2(0, 1);
  167.       (void) dup2(0, 2);
  168.       s = open("/dev/tty", 2);
  169.       if (s >= 0) {
  170.         (void) ioctl(s, TIOCNOTTY, (char *)0);
  171.         (void) close(s);
  172.       }
  173.     }
  174. #endif
  175.  
  176.     if (trace == ON) {
  177.         fd = fopen(tracefile, "w");
  178.         setlinebuf(fd);
  179.         fprintf(fd, "Tracing started on: %s\n\n", 
  180.                     date());
  181.     }
  182.  
  183.     srvp = getservbyname("timed", "udp");
  184.     if (srvp == 0) {
  185.         syslog(LOG_CRIT, "unknown service 'timed/udp'");
  186.         exit(1);
  187.     }
  188.     port = srvp->s_port;
  189.     server.sin_port = srvp->s_port;
  190.     server.sin_family = AF_INET;
  191.     sock = socket(AF_INET, SOCK_DGRAM, 0);
  192.     if (sock < 0) {
  193.         syslog(LOG_ERR, "socket: %m");
  194.         exit(1);
  195.     }
  196.     if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, 
  197.                             sizeof(on)) < 0) {
  198.         syslog(LOG_ERR, "setsockopt: %m");
  199.         exit(1);
  200.     }
  201.     if (bind(sock, &server, sizeof(server))) {
  202.         if (errno == EADDRINUSE)
  203.                 syslog(LOG_ERR, "server already running");
  204.         else
  205.                 syslog(LOG_ERR, "bind: %m");
  206.         exit(1);
  207.     }
  208.  
  209.     /* choose a unique seed for random number generation */
  210.     (void)gettimeofday(&time, (struct timezone *)0);
  211.     seed = time.tv_sec + time.tv_usec;
  212.     srandom(seed);
  213.  
  214.     sequence = random();     /* initial seq number */
  215.  
  216.     /* rounds kernel variable time to multiple of 5 ms. */
  217.     time.tv_sec = 0;
  218.     time.tv_usec = -((time.tv_usec/1000) % 5) * 1000;
  219.     (void)adjtime(&time, (struct timeval *)0);
  220.  
  221.     id = getpid();
  222.  
  223.     if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
  224.         syslog(LOG_ERR, "gethostname: %m");
  225.         exit(1);
  226.     }
  227.     hp[0].name = hostname;
  228.  
  229.     if (nflag || iflag) {
  230.         struct netent *getnetent();
  231.         struct netent *n;
  232.         struct nets *np;
  233.         for ( np = nets ; np ; np = np->next) {
  234.             n = getnetbyname(np->name);
  235.             if (n == NULL) {
  236.                 syslog(LOG_ERR, "getnetbyname: unknown net %s",
  237.                     np->name);
  238.                 exit(1);
  239.             }
  240.             np->net = n->n_net;
  241.         }
  242.     }
  243.     ifc.ifc_len = sizeof(buf);
  244.     ifc.ifc_buf = buf;
  245.     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
  246.         syslog(LOG_ERR, "get interface configuration: %m");
  247.         exit(1);
  248.     }
  249.     n = ifc.ifc_len/sizeof(struct ifreq);
  250.     ntp = NULL;
  251.     for (ifr = ifc.ifc_req; n > 0; n--, ifr++) {
  252.         if (ifr->ifr_addr.sa_family != AF_INET)
  253.             continue;
  254.         ifreq = *ifr;
  255.         if (ntp == NULL)
  256.             ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
  257.         ntp->my_addr = 
  258.             ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
  259.         if (ioctl(sock, SIOCGIFFLAGS, 
  260.                     (char *)&ifreq) < 0) {
  261.             syslog(LOG_ERR, "get interface flags: %m");
  262.             continue;
  263.         }
  264.         if ((ifreq.ifr_flags & IFF_UP) == 0 ||
  265.             ((ifreq.ifr_flags & IFF_BROADCAST) == 0 &&
  266.             (ifreq.ifr_flags & IFF_POINTOPOINT) == 0)) {
  267.             continue;
  268.         }
  269.         if (ifreq.ifr_flags & IFF_BROADCAST)
  270.             flag = 1;
  271.         else
  272.             flag = 0;
  273.         if (ioctl(sock, SIOCGIFNETMASK, 
  274.                     (char *)&ifreq) < 0) {
  275.             syslog(LOG_ERR, "get netmask: %m");
  276.             continue;
  277.         }
  278.         ntp->mask = ((struct sockaddr_in *)
  279.             &ifreq.ifr_addr)->sin_addr.s_addr;
  280.         if (flag) {
  281.             if (ioctl(sock, SIOCGIFBRDADDR, 
  282.                         (char *)&ifreq) < 0) {
  283.                 syslog(LOG_ERR, "get broadaddr: %m");
  284.                 continue;
  285.             }
  286.             ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
  287.         } else {
  288.             if (ioctl(sock, SIOCGIFDSTADDR, 
  289.                         (char *)&ifreq) < 0) {
  290.                 syslog(LOG_ERR, "get destaddr: %m");
  291.                 continue;
  292.             }
  293.             ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
  294.         }
  295.         ntp->dest_addr.sin_port = port;
  296.         if (nflag || iflag) {
  297.             u_long addr, mask;
  298.             struct nets *n;
  299.  
  300.             addr = ntohl(ntp->dest_addr.sin_addr.s_addr);
  301.             mask = ntohl(ntp->mask);
  302.             while ((mask & 1) == 0) {
  303.                 addr >>= 1;
  304.                 mask >>= 1;
  305.             }
  306.             for (n = nets ; n ; n = n->next)
  307.                 if (addr == n->net)
  308.                     break;
  309.             if (nflag && !n || iflag && n)
  310.                 continue;
  311.         }
  312.         ntp->net = ntp->mask & ntp->dest_addr.sin_addr.s_addr;
  313.         ntp->next = NULL;
  314.         if (nettab == NULL) {
  315.             nettab = ntp;
  316.         } else {
  317.             ntip->next = ntp;
  318.         }
  319.         ntip = ntp;
  320.         ntp = NULL;
  321.     }
  322.     if (ntp)
  323.         (void) free((char *)ntp);
  324.     if (nettab == NULL) {
  325.         syslog(LOG_ERR, "No network usable");
  326.         exit(1);
  327.     }
  328.  
  329.     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  330.         lookformaster(ntp);
  331.     setstatus();
  332.     /*
  333.      * Take care of some basic initialization.
  334.      */
  335.     /* us. delay to be used in response to broadcast */
  336.     delay1 = casual((long)10000, 200000);    
  337.  
  338.     /* election timer delay in secs. */
  339.     delay2 = casual((long)MINTOUT, (long)MAXTOUT);
  340.  
  341.     if (Mflag) {
  342.         /*
  343.          * number (increased by 1) of slaves controlled by master: 
  344.          * used in master.c, candidate.c, networkdelta.c, and 
  345.          * correct.c 
  346.          */
  347.         slvcount = 1;
  348.         ret = setjmp(jmpenv);
  349.  
  350.         switch (ret) {
  351.  
  352.         case 0: 
  353.             makeslave(firstslavenet());
  354.             setstatus();
  355.             break;
  356.         case 1: 
  357.             /* Just lost our master */
  358.             setstatus();
  359.             slavenet->status = election(slavenet);
  360.             checkignorednets();
  361.             setstatus();
  362.             if (slavenet->status == MASTER)
  363.                 makeslave(firstslavenet());
  364.             else
  365.                 makeslave(slavenet);
  366.             setstatus();
  367.             break;
  368.         case 2:
  369.             /* Just been told to quit */
  370.             fromnet->status = SLAVE;
  371.             setstatus();
  372.             savefromnet = fromnet;
  373.             rmnetmachs(fromnet);
  374.             checkignorednets();
  375.             if (slavenet)
  376.                 makeslave(slavenet);
  377.             else
  378.                 makeslave(savefromnet);
  379.             setstatus();
  380.             justquit = 1;
  381.             break;
  382.             
  383.         default:
  384.             /* this should not happen */
  385.             syslog(LOG_ERR, "Attempt to enter invalid state");
  386.             break;
  387.         }
  388.             
  389.         if (status & MASTER) {
  390.             /* open raw socket used to measure time differences */
  391.             if (sock_raw == -1) {
  392.                 sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
  393.                 if (sock_raw < 0)  {
  394.                     syslog(LOG_ERR, "opening raw socket: %m");
  395.                     exit (1);
  396.                 }
  397.             }
  398.         } else {
  399.             /* sock_raw is not being used now */
  400.             if (sock_raw != -1) {
  401.                 (void)close(sock_raw);
  402.                 sock_raw = -1;
  403.             }
  404.         }
  405.  
  406.         if (status == MASTER) 
  407.             master();
  408.         else 
  409.             slave();
  410.     } else {
  411.         /* if Mflag is not set timedaemon is forced to act as a slave */
  412.         status = SLAVE;
  413.         if (setjmp(jmpenv)) {
  414.             setstatus();
  415.             checkignorednets();
  416.         }
  417.         makeslave(firstslavenet());
  418.         for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  419.             if (ntp->status == MASTER)
  420.                 ntp->status = IGNORE;
  421.         setstatus();
  422.         slave();
  423.     }
  424. }
  425.  
  426. /*
  427.  * Try to become master over ignored nets..
  428.  */
  429. checkignorednets()
  430. {
  431.     register struct netinfo *ntp;
  432.     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  433.         if (ntp->status == IGNORE)
  434.             lookformaster(ntp);
  435. }
  436.  
  437. lookformaster(ntp)
  438.     register struct netinfo *ntp;
  439. {
  440.     struct tsp resp, conflict, *answer, *readmsg(), *acksend();
  441.     struct timeval time;
  442.     char mastername[MAXHOSTNAMELEN];
  443.     struct sockaddr_in masteraddr;
  444.  
  445.     ntp->status = SLAVE;
  446.     /* look for master */
  447.     resp.tsp_type = TSP_MASTERREQ;
  448.     (void)strcpy(resp.tsp_name, hostname);
  449.     answer = acksend(&resp, &ntp->dest_addr, (char *)ANYADDR, 
  450.         TSP_MASTERACK, ntp);
  451.     if (answer == NULL) {
  452.         /*
  453.          * Various conditions can cause conflict: race between
  454.          * two just started timedaemons when no master is
  455.          * present, or timedaemon started during an election.
  456.          * Conservative approach is taken: give up and became a
  457.          * slave postponing election of a master until first
  458.          * timer expires.
  459.          */
  460.         time.tv_sec = time.tv_usec = 0;
  461.         answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR,
  462.             &time, ntp);
  463.         if (answer != NULL) {
  464.             ntp->status = SLAVE;
  465.             return;
  466.         }
  467.  
  468.         time.tv_sec = time.tv_usec = 0;
  469.         answer = readmsg(TSP_MASTERUP, (char *)ANYADDR,
  470.             &time, ntp);
  471.         if (answer != NULL) {
  472.             ntp->status = SLAVE;
  473.             return;
  474.         }
  475.  
  476.         time.tv_sec = time.tv_usec = 0;
  477.         answer = readmsg(TSP_ELECTION, (char *)ANYADDR,
  478.             &time, ntp);
  479.         if (answer != NULL) {
  480.             ntp->status = SLAVE;
  481.             return;
  482.         }
  483.         ntp->status = MASTER;
  484.     } else {
  485.         (void)strcpy(mastername, answer->tsp_name);
  486.         masteraddr = from;
  487.  
  488.         /*
  489.          * If network has been partitioned, there might be other
  490.          * masters; tell the one we have just acknowledged that 
  491.          * it has to gain control over the others. 
  492.          */
  493.         time.tv_sec = 0;
  494.         time.tv_usec = 300000;
  495.         answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time,
  496.             ntp);
  497.         /*
  498.          * checking also not to send CONFLICT to ack'ed master
  499.          * due to duplicated MASTERACKs
  500.          */
  501.         if (answer != NULL && 
  502.             strcmp(answer->tsp_name, mastername) != 0) {
  503.             conflict.tsp_type = TSP_CONFLICT;
  504.             (void)strcpy(conflict.tsp_name, hostname);
  505.             if (acksend(&conflict, &masteraddr, mastername,
  506.                 TSP_ACK, (struct netinfo *)NULL) == NULL) {
  507.                 syslog(LOG_ERR, 
  508.                     "error on sending TSP_CONFLICT");
  509.                 exit(1);
  510.             }
  511.         }
  512.     }
  513. }
  514. /*
  515.  * based on the current network configuration, set the status, and count
  516.  * networks;
  517.  */
  518. setstatus()
  519. {
  520.     register struct netinfo *ntp;
  521.  
  522.     status = 0;
  523.     nmasternets = nslavenets = nnets = nignorednets = 0;
  524.     if (trace)
  525.         fprintf(fd, "Net status:\n");
  526.     for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
  527.         switch ((int)ntp->status) {
  528.           case MASTER:
  529.             nmasternets++;
  530.             break;
  531.           case SLAVE:
  532.             nslavenets++;
  533.             break;
  534.           case IGNORE:
  535.             nignorednets++;
  536.             break;
  537.         }
  538.         if (trace) {
  539.             fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
  540.             switch ((int)ntp->status) {
  541.               case MASTER:
  542.                 fprintf(fd, "MASTER\n");
  543.                 break;
  544.               case SLAVE:
  545.                 fprintf(fd, "SLAVE\n");
  546.                 break;
  547.               case IGNORE:
  548.                 fprintf(fd, "IGNORE\n");
  549.                 break;
  550.               default:
  551.                 fprintf(fd, "invalid state %d\n",(int)ntp->status);
  552.                 break;
  553.             }
  554.         }
  555.         nnets++;
  556.         status |= ntp->status;
  557.     }
  558.     status &= ~IGNORE;
  559.     if (trace)
  560.         fprintf(fd,
  561.               "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
  562.               nnets, nmasternets, nslavenets, nignorednets);
  563. }
  564.  
  565. makeslave(net)
  566.     struct netinfo *net;
  567. {
  568.     register struct netinfo *ntp;
  569.  
  570.     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  571.         if (ntp->status == SLAVE && ntp != net)
  572.             ntp->status = IGNORE;
  573.     slavenet = net;
  574. }
  575.     
  576. struct netinfo *
  577. firstslavenet()
  578. {
  579.     register struct netinfo *ntp;
  580.  
  581.     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  582.         if (ntp->status == SLAVE)
  583.             return (ntp);
  584.     return ((struct netinfo *)0);
  585. }
  586.  
  587. /*
  588.  * `casual' returns a random number in the range [inf, sup]
  589.  */
  590.  
  591. long
  592. casual(inf, sup)
  593. long inf;
  594. long sup;
  595. {
  596.     float value;
  597.  
  598.     value = (float)(random() & 0x7fffffff) / 0x7fffffff;
  599.     return(inf + (sup - inf) * value);
  600. }
  601.  
  602. char *
  603. date()
  604. {
  605.     char    *ctime();
  606.     struct    timeval tv;
  607.  
  608.     (void)gettimeofday(&tv, (struct timezone *)0);
  609.     return (ctime(&tv.tv_sec));
  610. }
  611.  
  612. addnetname(name)
  613.     char *name;
  614. {
  615.     register struct nets **netlist = &nets;
  616.  
  617.     while (*netlist)
  618.         netlist = &((*netlist)->next);
  619.     *netlist = (struct nets *)malloc(sizeof **netlist);
  620.     if (*netlist == (struct nets *)0) {
  621.         syslog(LOG_ERR, "malloc failed");
  622.         exit(1);
  623.     }
  624.     bzero((char *)*netlist, sizeof(**netlist));
  625.     (*netlist)->name = name;
  626. }
  627.